package com.lwd.spring.study.bean;

import com.lwd.spring.study.entity.User;
import com.lwd.spring.study.service.UserService;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.*;
import org.springframework.context.weaving.LoadTimeWeaverAware;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;
import org.springframework.web.context.ServletConfigAware;
import org.springframework.web.context.ServletContextAware;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
 * @Author: 刘东（挂兰）
 * @Date: 2023/12/12 21:48:32
 * @Description: spring 回掉使用了该接口的类 ApplicationContextAware
 * 需要@Component等注解修饰
 * 重要的
 * ApplicationContextAware
 * ServletContextAware
 * EnvironmentAware
 * <p>
 * ApplicationContextAware接口可以让Bean获取到ApplicationContext对象，通过这个对象，我们可以获取Spring容器中的其他Bean实例或一些组件。常见的应用场景包括：
 * <p>
 * 在Web项目中获取ServletContext
 * 获取国际化信息
 * 获取Scheduler等定时任务
 * <p>
 */

/**
 * ApplicationContextAware接口可以让Bean获取到ApplicationContext对象，通过这个对象，我们可以获取Spring容器中的其他Bean实例或一些组件。常见的应用场景包括：
 *
 * 在Web项目中获取ServletContext
 * 获取国际化信息
 * 获取Scheduler等定时任务
 */
@Component
public class MyBean implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        UserService bean = applicationContext.getBean(UserService.class);
        User user = bean.getUser();
        System.out.println("user = " + user);
    }
}

/**
 * BeanFactoryAware接口可以让Bean获取到BeanFactory对象，通过这个对象，我们可以获取Spring容器中的Bean实例或一些组件。常见的应用场景包括：
 *
 * 获取Spring容器中的Bean实例
 * 手动注册BeanDefinition
 */
//@Component
//public class MyBean implements BeanFactoryAware {
//
//    @Override
//    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
//        UserService bean = beanFactory.getBean(UserService.class);
//        User user = bean.getUser();
//        System.out.println("user2 = " + user);
//    }
//}

/**
 * MessageSourceAware接口可以让Bean获取到MessageSource对象，通过这个对象，我们可以方便地进行国际化操作。常见的应用场景包括：
 *
 * 获取国际化信息
 */
//@Component
//public class MyBean implements MessageSourceAware {
//
//    private MessageSource messageSource;
//
//    @Override
//    public void setMessageSource(MessageSource messageSource) {
//        this.messageSource = messageSource;
//        // 获取国际化信息
//        // String message = messageSource.getMessage("message.hello", null, Locale.getDefault());
//
//    }
//}

/**
 * ResourceLoaderAware接口可以让Bean获取到ResourceLoader对象，通过这个对象，我们可以方便地进行资源加载操作。常见的应用场景包括：
 *
 * 加载配置文件
 * 加载图片等静态资源
 */
//@Component
//public class MyBean implements ResourceLoaderAware {
//
//    private ResourceLoader resourceLoader;
//
//    @Override
//    public void setResourceLoader(ResourceLoader resourceLoader) {
//
//    }
//
//}

/**
 * ServletContextAware接口可以让Bean获取到ServletContext对象，通过这个对象，我们可以方便地进行Web项目开发。常见的应用场景包括：
 *
 * 获取Web项目的一些信息，如上下文路径等
 */
//public class MyBean implements ServletContextAware {
//    private ServletContext servletContext;
//
//    @Override
//    public void setServletContext(ServletContext servletContext) {
//        this.servletContext = servletContext;
//    }
//
//    public void doSomething() {
//        // 获取上下文路径
//        String contextPath = servletContext.getContextPath();
//        // ...
//    }
//}


/**
 * EnvironmentAware接口可以让Bean获取到Environment对象，通过这个对象，我们可以方便地获取Spring的环境配置信息。常见的应用场景包括：
 *
 * 获取当前的环境配置，如开发环境、测试环境或生产环境
 * 获取配置文件中的属性值
 */
//public class MyBean implements EnvironmentAware {
//    private Environment environment;
//
//    @Override
//    public void setEnvironment(Environment environment) {
//        this.environment = environment;
//    }
//
//    public void doSomething() {
//        // 获取当前环境
//        String profile = environment.getActiveProfiles()[0];
//        // 获取配置文件中的属性值
//        String value = environment.getProperty("key");
//        // ...
//    }
//}


/**
 * ServletConfigAware接口可以让Bean获取到ServletConfig对象，通过这个对象，我们可以方便地获取Servlet的相关信息。常见的应用场景包括：
 *
 * 获取Servlet的名称
 * 获取Servlet的初始化参数
  */
//public class MyBean extends HttpServlet implements ServletConfigAware {
//
//    private ServletConfig servletConfig;
//
//    @Override
//    public void setServletConfig(ServletConfig servletConfig) {
//        this.servletConfig = servletConfig;
//    }
//
//    @Override
//    public void doGet(HttpServletRequest request, HttpServletResponse response) {
//        // 获取Servlet的名称
//        String servletName = servletConfig.getServletName();
//        // 获取Servlet的初始化参数
//        String value = servletConfig.getInitParameter("key");
//        // ...
//    }
//}

/**
 * ApplicationContextInitializer接口是Spring提供的一个接口，
 * 我们可以在Spring容器初始化之前做一些必要的操作，常见的应用场景包括：
 *
 * 修改配置信息
 * 注册BeanDefinition
  */
//public class MyApplicationContextInitializer implements ApplicationContextInitializer {
//    @Override
//    public void initialize(ConfigurableApplicationContext applicationContext) {
//        // 注册BeanDefinition
//        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
//        beanDefinition.setBeanClass(OtherBean.class);
//        beanDefinition.setPropertyValues(new MutablePropertyValues());
//        ((DefaultListableBeanFactory) applicationContext.getBeanFactory()).registerBeanDefinition("otherBean", beanDefinition);
//        // ...
//    }
//}


/**
 * EmbeddedValueResolverAware接口可以让Bean获取到EmbeddedValueResolver对象，通过这个对象，我们可以方便地替换属性占位符。常见的应用场景包括：
 *
 * 替换配置文件中的占位符
 */
//public class MyBean implements EmbeddedValueResolverAware {
//    private StringValueResolver stringValueResolver;
//
////    @Override
////    public void setEmbeddedValueResolver(EmbeddedValueResolver embeddedValueResolver) {
////        this.embeddedValueResolver = embeddedValueResolver;
////    }
//
//    public void doSomething() {
//        // 获取属性值
//        String value = stringValueResolver.resolveStringValue("${key}");
//        // ...
//    }
//
//    @Override
//    public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
//
//    }
//}

/**
 * LoadTimeWeaverAware接口可以让Bean获取到LoadTimeWeaver对象，通过这个对象，我们可以实现类的动态加载。常见的应用场景包括：
 *
 * 动态加载类
 */
//public class MyBean implements LoadTimeWeaverAware {
//    private LoadTimeWeaver loadTimeWeaver;
//
//    @Override
//    public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
//        this.loadTimeWeaver = loadTimeWeaver;
//    }
//
//    public void doSomething() throws ClassNotFoundException {
//        // 动态加载类
//        ClassLoader classLoader = loadTimeWeaver.getInstrumentableClassLoader();
//        Class<?> aClass = classLoader.loadClass("com.lwd.spring.study.entity.User");
//        // ...
//    }
//}

/**
 * ConversionServiceAware接口可以让Bean获取到ConversionService对象，通过这个对象，我们可以方便地进行类型转换。常见的应用场景包括：
 *
 * 类型转换
 * 数据校验
 * ConversionServiceAware接口已经不存在
 */
//public class MyBean implements ConversionServiceAware {
//    private ConversionService conversionService;
//
//    @Override
//    public void setConversionService(ConversionService conversionService) {
//        this.conversionService = conversionService;
//    }
//
//    public void doSomething() {
//        // 类型转换
//        String str = "123";
//        Integer value = conversionService.convert(str, Integer.class);
//        // ...
//    }
//}